package eiisan.config.aop.exception.advisor;

import eiisan.config.aop.exception.annotation.CatchAndReturn;
import eiisan.config.aop.util.AOPUtil;
import eiisan.util.common.StrUtil;
import eiisan.util.model.response.Result;
import eiisan.util.reflect.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Slf4j
@Component
@Order(Integer.MIN_VALUE)
public class AsyncCatchAndReturnAdvisor implements PointcutAdvisor {

    @Override
    public Advice getAdvice() {
        return (MethodInterceptor) invocation -> {
            try {
                return invocation.proceed();
            } catch (Exception e) {
                log.error(StrUtil.concat("[", ReflectUtil.getFullMethodName(invocation.getMethod()), "]"), e);
                return Result.errorServe().async();
            }
        };
    }

    @Override
    public boolean isPerInstance() {
        return true;
    }

    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {

            /**
             * 根据方法判断
             */
            @Override
            public MethodMatcher getMethodMatcher() {
                return new MethodMatcher() {

                    /**
                     * 对方法进行判断(运行时)
                     */
                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        //isRuntime()方法返回值为false时,不会进行运行时判断
                        return false;
                    }

                    /**
                     * 对方法进行判断
                     */
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        //这里可以进行运行前检查
                        return method.isAnnotationPresent(CatchAndReturn.class) && AOPUtil.isAsyncResultAsReturn(
                                method);
                    }

                    /**
                     * 默认true
                     */
                    @Override
                    public boolean isRuntime() {
                        return false;
                    }
                };
            }

            /**
             * 根据类型判断
             */
            @Override
            public ClassFilter getClassFilter() {
                return clazz -> true;
            }

        };
    }

}
